﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.SQLite;
using System.Text.RegularExpressions;

namespace Ruandao.MiniAccess.SQLite3
{
    public class SQLiteDatabase : Database
    {
        /// <summary>
        /// 根据一个连接字符串初始化一个SQLiteDatabase的实例
        /// </summary>
        /// <param name="connectionString"></param>
        public SQLiteDatabase(string connectionString)
            : base(connectionString, SQLiteFactory.Instance)
        {

        }

        /// <summary>
        /// 获取命令
        /// </summary>
        /// <param name="storedProcedureName"></param>
        /// <returns></returns>
        public override DbCommand GetStoredProcCommand(string storedProcedureName)
        {
            return this.GetStoredProcCommand(storedProcedureName, null);
        }

        /// <summary>
        /// 根据带参sqlText,返回DbCommand
        /// </summary>
        /// <param name="storedProcedureName"></param>
        /// <param name="parameterValues"></param>
        /// <returns></returns>
        public override DbCommand GetStoredProcCommand(string storedProcedureName, params object[] parameterValues)
        {
            return GetCommandTextCommand(storedProcedureName, parameterValues);
        }

        #region Util

        /// <summary>
        /// 获取CommandText命令
        /// </summary>
        /// <param name="storedProcedureName"></param>
        /// <param name="parameterValues"></param>
        /// <returns></returns>
        private DbCommand GetCommandTextCommand(string storedProcedureName, object[] parameterValues)
        {
            //生成DbParameter列表
            List<DbParameter> parameterList = CombineSqlText(ref storedProcedureName, parameterValues);

            //生成CommandText命令
            DbCommand command = GetSqlStringCommand(storedProcedureName);

            //插入参数
            command.Parameters.AddRange(parameterList.ToArray());

            return command;
        }

        /// <summary>
        /// 重组sqlText,生成DbParameter
        /// </summary>
        /// <param name="sqlText"></param>
        /// <param name="templateArgs"></param>
        /// <returns></returns>
        private static List<DbParameter> CombineSqlText(ref string sqlText, object[] templateArgs)
        {
            List<int> numList;
            List<DbParameter> parameterList;

            GetParameters(sqlText, templateArgs, out numList, out parameterList);

            sqlText = ReplaceConditionTemplate(sqlText, numList, parameterList);
            return parameterList;
        }

        private static string ReplaceConditionTemplate(string conditionTemplate, List<int> numList, List<DbParameter> parameterList)
        {
            //替换原条件字符串中的占位符
            foreach (var num in numList)
            {
                conditionTemplate = Regex.Replace(conditionTemplate, "\\{" + num + "\\}", parameterList[num].ParameterName, RegexOptions.Multiline);
            }
            return conditionTemplate;
        }

        private static void GetParameters(string conditionTemplate, object[] templateArgs, out List<int> numList, out List<DbParameter> parameterList)
        {
            //用正则表达式捕获参数模板

            MatchCollection matches = Regex.Matches(conditionTemplate, @"\{\d+\}", RegexOptions.Multiline);
            numList = new List<int>();
            foreach (Match item in matches)
            {
                int num = int.Parse(Regex.Match(item.Value, @"\d+", RegexOptions.Multiline).Value);
                if (num >= templateArgs.Length)
                {
                    throw new Exception("格式错误或参数数量不对称");
                }
                if (!numList.Contains(num))
                {
                    numList.Add(num);
                }
            }

            //生成SqlParameter 列表
            parameterList = new List<DbParameter>();
            foreach (var num in numList)
            {
                DbParameter parameter = new SQLiteParameter("@value" + num, templateArgs[num]);
                parameterList.Add(parameter);
            }
        }
        #endregion

        protected override void DeriveParameters(DbCommand discoveryCommand)
        {
            throw new Exception("不支持方法");
        }

        public override void CreateProcedure(string procedureName, string parametersText, string bodyText, bool isDebug)
        {
            throw new Exception("不支持方法");
        }
    }
}
